public class Solution892 {
    /**
     * 在 N * N 的网格上，我们放置一些 1 * 1 * 1  的立方体。
     * <p>
     * 每个值 v = grid[i][j] 表示 v 个正方体叠放在对应单元格 (i, j) 上。
     * <p>
     * 请你返回最终形体的表面积。
     * <p>
     * 示例 1：
     * <p>
     * 输入：[[2]]
     * 输出：10
     * 示例 2：
     * <p>
     * 输入：[[1,2],[3,4]]
     * 输出：34
     * 示例 3：
     * <p>
     * 输入：[[1,0],[0,2]]
     * 输出：16
     * 示例 4：
     * <p>
     * 输入：[[1,1,1],[1,0,1],[1,1,1]]
     * 输出：32
     * 示例 5：
     * <p>
     * 输入：[[2,2,2],[2,1,2],[2,2,2]]
     * 输出：46
     */

    public int surfaceArea(int[][] grid) {
        int rows = grid.length;
        if (rows == 0) return 0;
        int cols = grid[0].length;
        int sum = 0;
        boolean[][] help = new boolean[rows][cols];
        for (int row = 0; row < rows; row++) {
            for (int col = 0; col < cols; col++) {
                help[row][col] = true;
                if (grid[row][col] > 0) {
                    sum += 4 * grid[row][col] + 2;
                    sum -= find(grid, row - 1, col, rows, cols, help, grid[row][col]) +
                            find(grid, row + 1, col, rows, cols, help, grid[row][col]) +
                            find(grid, row, col - 1, rows, cols, help, grid[row][col]) +
                            find(grid, row, col + 1, rows, cols, help, grid[row][col]);
                }
            }
        }
        return sum;
    }

    public int find(int[][] grid, int row, int col, int rows, int cols, boolean[][] help, int v) {
        if (row < 0 || col < 0 || row >= rows || col >= cols || help[row][col]) {
            return 0;
        }
        return Math.min(v, grid[row][col]) * 2;
    }
}
